#ifndef SOCKET_H_INCLUDED
#define SOCKET_H_INCLUDED
#include "Configuracion.h"
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include "Thread.h"
#include <string>

#define PUERTO_NO_ABIERTO -1
#define SOCKET_NO_ABIERTO -1

typedef int t_puerto;

class Socket {
public:
    Socket();
    explicit Socket(int fd_socket);
    virtual ~Socket();
    /* Getters y Setters */
    t_puerto getPuerto() {
        return this->puerto;
    }
    int getSocket() {
        return this->socketfd;
    }
    std::string getDireccion() {
        return this->direccion;
    }
    void setSocket(int socketfd) {
        this->socketfd = socketfd;
    }
    void setPuerto(t_puerto puerto=-1) {
        this->puerto= puerto;
    }
    void setDireccion(std::string direccion) {
        this->direccion= direccion;
    }
    /** Descripcion: recibe en "buffer" mensaje enviado por cliente.
    *   Retorno: -1 -> error, >0 -> exito: cant. bytes recibidos
    */
//        virtual int recibir(char** buffer);
    int recibir(char* buffer_entrada, uint32_t tamanio);
    /** Descripcion: envia "mensaje" de tamanio "tamanio".
    *   Retorno: -1 -> error, >0 -> exito: cant. bytes enviados
    */
    int enviar(char* mensaje, uint32_t tamanio);

    /** Descripcion: envia el mensaje pasado por parametro de tamanio "tamanio"
    enviando previamente notificacion de tamanio en formato Big Indian.
    Retorno: (idem enviar)
    */
    int enviarConAvisoDeLong(char* mensaje, uint32_t tamanio);

    /** Descripcion: recibe en el buffer pasado por parametro un mensaje de tamanio
    menor o igual al tamanio del mismo.
    Retorno: (idem enviar), -3: el buffer es insuficiente para almacenar mensaje.
    */
    int recibirConAvisoDeLong(char* buffer, uint32_t tamanio_buffer);


    virtual int conectar();

    //virtual void* run() = 0;

    void cerrar();
    void apagar();
    virtual std::string aString();

    void imprimir();
    bool estaConectado();
    /** Descripcion: setea estructuras necesarias para conexion.
    *   Retorno: 1 -> error, 0 -> exito
    */
    int setAddrInfo();
    /** Descripcion: obtiene un file descriptor para el socket y lo
    *   setea en atributo "socketfd" en caso de exito.
    *   PRE: debio ejecutarse setAddrInfo previamente.
    *   Retorno: 1 -> error, 0 -> exito
    */
    int getSocketDescriptor();

protected:
    struct addrinfo host_info;
    struct addrinfo *host_info_list;
private:
    int socketfd;
    t_puerto puerto;
    std::string direccion;

    void inicializar();
};

#endif // SOCKET_H_INCLUDED
